﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.SharePoint;

using SharePointEnforcer.Rules;
using SharePointEnforcer.Utilities;

namespace SharePointEnforcer
{

    class RuleManager
    {
        protected bool _hasRunSiteRules = false;
        protected EnforcerSettings _settings;

        protected EnforcerRuleItemCollection _Rules = new EnforcerRuleItemCollection();

        public RuleManager(EnforcerSettings pSettings)
        {
            _settings = pSettings;
            LoadRules();
        }

        public RuleManager(SiteRuleNode pSite)
        {
            foreach (string rulepath in pSite.RulePaths)
            {
                XmlDocument doc = EnforcerUtils.Xml.LoadXmlDoc(rulepath);
            }
        }

        private void LoadRules()
        {
            // ~~ testing only
            _Rules.Add(new ForceExplicitSecurity(), EnforcerRuleScope.NonRootWeb);
        }

        protected void ProcessSiteRules(SPSite pSite)
        {
            if (pSite == null || _hasRunSiteRules) return;
            _hasRunSiteRules = true;
            ApplyRules(EnforcerRuleScope.Site, pSite.RootWeb);

            // now apply rules for the root only
            if (pSite.RootWeb != null) ApplyRules(EnforcerRuleScope.RootWeb, pSite.RootWeb);
        }



        public void ProcessRules(SPWeb pWeb)
        {
            if (pWeb == null) return;
            if (!_hasRunSiteRules) ProcessSiteRules(pWeb.Site);

            if (!pWeb.IsRootWeb) ApplyRules(EnforcerRuleScope.NonRootWeb, pWeb);
        }


        private void ApplyRules(EnforcerRuleScope pScope, SPWeb pWeb)
        {
            foreach (EnforcerRuleItem rule in _Rules)
            {
                if ((rule.Scope & pScope) == pScope)
                {
                    using (EnforcerArg arg = new EnforcerArg(pWeb))
                    {
                        rule.Item.Evaluate(arg);

                        // if it failed, try to repair it (if the rule supports that)
                        if (arg.RepairState == EnforcerRepairResult.RepairRequired)
                        {
                            if (!_settings.WhatIf) rule.Item.Repair(arg);
                        }
                    }
                }
            }
        }
    }


    public enum EnforcerRuleScope : int
    {
        Site = 1,
        RootWeb = 2,
        NonRootWeb = 4,
        AllWebs = 6,
        Unknown = 128
    }


    class EnforcerRuleItemCollection : List<EnforcerRuleItem>
    {
        public void Add(iEnforcerRule pRule, EnforcerRuleScope pScope)
        {
            this.Add(new EnforcerRuleItem(pRule, pScope));
        }
    }


    class EnforcerRuleItem
    {
        public EnforcerRuleItem(iEnforcerRule pRule, EnforcerRuleScope pScope)
        {
            Item = pRule;
            Scope = pScope;
        }

        public iEnforcerRule Item { get; protected set; }
        public EnforcerRuleScope Scope { get; protected set; }
    }

}
